package com.luoke.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import com.luoke.constant.ModuleTypeConstant;
import com.luoke.constant.StatusConstant;
import com.luoke.constant.SubmoduleTypeConstant;
import com.luoke.context.GlobalDataStore;
import com.luoke.dao.BattleDao;
import com.luoke.dao.UserDao;
import com.luoke.dao.UserPetDao;
import com.luoke.dao.impl.BattleDaoImpl;
import com.luoke.dao.impl.UserDaoImpl;
import com.luoke.dao.impl.UserPetDaoImpl;
import com.luoke.pojo.dto.InitiateBattleDTO;
import com.luoke.pojo.entity.UserPet;
import com.luoke.result.Result;
import com.luoke.service.BattleResponseService;
import com.luoke.util.BattleUtils;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.WebSocket;

import java.util.List;

/**
 * 对战斗请求响应的服务层
 */
@Slf4j
public class BattleResponseServiceImpl implements BattleResponseService {

    private final BattleDao battleDao = new BattleDaoImpl();
    private final UserDao userDao = new UserDaoImpl();
    private final UserPetDao userPetDao = new UserPetDaoImpl();

    /**
     * 拿到所有的在线用户并返回给客户端
     *
     * @param conn   与客户端的通信对象
     * @param result 客户端数据
     */
    @Override
    public void showUserOnlineName(WebSocket conn, Result result) {
        List<String> onlinePlayers = userDao.getOnlinePlayers();
        StringBuilder online = new StringBuilder("当前在线的玩家为:");
        for (String player : onlinePlayers) {
            online.append(player).append(",");
        }
//        Result<String> response = new Result<>();
//        response.setStatus(StatusConstant.SUCCESS);
//        response.setCommand(SubmoduleTypeConstant.SHOW_USER_WAIT_ONLINE_NAME);
//        response.setModuleName(ModuleTypeConstant.BATTLE);
//        response.setData(online.toString());

        //结果集响应给客户端
        conn.send(JSONUtil.toJsonStr(Result.success(SubmoduleTypeConstant.SHOW_USER_WAIT_ONLINE_NAME, ModuleTypeConstant.BATTLE, "服务端处理成功", online.toString())));


    }

    /**
     * 处理对战请求，发送给对应的客户端
     *
     * @param conn   与客户端的通信对象
     * @param result 客户端数据
     */
    @Override
    public void battleRequest(WebSocket conn, Result result) {
        //对对象进行处理
        result.setData(JSONUtil.toBean(result.getData().toString(), InitiateBattleDTO.class));
        InitiateBattleDTO data = (InitiateBattleDTO) result.getData();
        Result response = new Result();
        //这里要判断对手是否在等待区中
        if (GlobalDataStore.waitUser.get(data.getOpponentName()) == null) {
            //对手不在等待区中  响应一个不在等待的状态
            response.setModuleName(ModuleTypeConstant.BATTLE);
            response.setStatus(StatusConstant.NO_WAIT);
            response.setCommand(SubmoduleTypeConstant.INITIATE_BATTLE_REQUEST);
            GlobalDataStore.onlineUser.get(data.getInitiatorName()).send(JSONUtil.toJsonStr(response));//在等待区中没有找到对应的的玩家的话，响应给发起人，提示NO_WAIT
        } else {
            //对手在等待区中  发送对战邀请
            response.setModuleName(ModuleTypeConstant.BATTLE);
            response.setCommand(SubmoduleTypeConstant.ACCEPT_BATTLE_INVITATION);//向对应客户端发起一个对战邀请
            response.setData(data);
            GlobalDataStore.onlineUser.get(data.getOpponentName()).send(JSONUtil.toJsonStr(response));//从在线玩家中找到对应玩家发送消息
        }


    }

    /**
     * 对对方玩家同意或拒绝的请求的处理
     *
     * @param conn   与客户端的通信对象
     * @param result 客户端数据
     */
    @Override
    public void acceptBattleRequest(WebSocket conn, Result result) {
        result.setData(JSONUtil.toBean(result.getData().toString(), InitiateBattleDTO.class));
        InitiateBattleDTO data = (InitiateBattleDTO) result.getData();
        Result response = new Result();
        if (data.getIsAccept().equals("accept")) {
            response.setModuleName(ModuleTypeConstant.BATTLE);
            response.setStatus(StatusConstant.SUCCESS);
            if (data.getIsMatch()) {
                response.setCommand(SubmoduleTypeConstant.MATCH_BATTLE);//给发起对战的用户 响应
            } else {
                response.setCommand(SubmoduleTypeConstant.INITIATE_BATTLE_REQUEST);//给发起对战的用户 响应
            }
            response.setData(data);
            GlobalDataStore.onlineUser.get(data.getInitiatorName()).send(JSONUtil.toJsonStr(response)); //给发起用户响应
            //同意对战之后，要把用户从等待区中移除
            if (GlobalDataStore.waitUser.get(data.getOpponentName()) != null) { //判断防止空指针
                GlobalDataStore.waitUser.remove(data.getOpponentName());
            }


            //同意对战之后要同时给双方发送所携带的宠物列表
            sendUserPetInfo(data);
            //同意对战之后要初始化战斗表和战斗宠物表
            Long primaryId = initBattleTableAndBPetTable(data);
//            GlobalDataStore.setBattleId(l);

            //要把双方的name和战斗id进行一个绑定  2024年11月27日13:32:55
            GlobalDataStore.addPlayerToBattleId(data.getInitiatorName(), primaryId);
            GlobalDataStore.addPlayerToBattleId(data.getOpponentName(), primaryId);


//            GlobalDataStore.battleId=l;

        } else {
            response.setModuleName(ModuleTypeConstant.BATTLE);
            response.setStatus(StatusConstant.FAIL);
            if (data.getIsMatch()) {
                response.setCommand(SubmoduleTypeConstant.MATCH_BATTLE);//给发起对战的用户 响应
            } else {
                response.setCommand(SubmoduleTypeConstant.INITIATE_BATTLE_REQUEST);//给发起对战的用户 响应
            }
            response.setData(data);
            GlobalDataStore.onlineUser.get(data.getInitiatorName()).send(JSONUtil.toJsonStr(response));
            //同意拒绝对战之后，也要把用户从等待区中移除
            if (GlobalDataStore.waitUser.get(data.getOpponentName()) != null) { //判断防止空指针
                GlobalDataStore.waitUser.remove(data.getOpponentName());
            }
        }
    }

    /**
     * 把用户加入等待阶段
     *
     * @param conn   与客户端的通信对象
     * @param result 客户端数据
     */
    @Override
    public void waitForUser(WebSocket conn, Result result) {
        GlobalDataStore.waitUser.put(result.getData().toString(), StatusConstant.WAIT);//把用户加入等待区
    }

    /**
     * 把等待区的用户响应给客户端
     *
     * @param conn   与客户端的通信对象
     * @param result 客户端数据
     */
    @Override
    public void showWaitForUser(WebSocket conn, Result result) {
        StringBuilder waitUser = new StringBuilder("当前在等待区的玩家为:");
        for (String userName : GlobalDataStore.waitUser.keySet()) {
            waitUser.append(" ").append(userName);
        }
        //结果集响应给客户端
        conn.send(JSONUtil.toJsonStr(Result.success(SubmoduleTypeConstant.SHOW_WAIT_FOR_USER, ModuleTypeConstant.BATTLE, "服务端处理成功", waitUser.toString())));
    }

    /**
     * 这里处理的是匹配对战的请求
     *
     * @param conn   与客户端的通信对象
     * @param result 客户端数据
     */
    @Override
    public void matchBattle(WebSocket conn, Result result) {

        result.setData(JSONUtil.toBean(result.getData().toString(), InitiateBattleDTO.class));
        InitiateBattleDTO data = (InitiateBattleDTO) result.getData();
        data.setIsMatch(true);//标记是从匹配入口进入的
        //判断等待区中是否为空
        if (MapUtil.isEmpty(GlobalDataStore.waitUser)) {
            //如果为空则通知客户端
            conn.send(JSONUtil.toJsonStr(Result.fail(SubmoduleTypeConstant.MATCH_BATTLE, ModuleTypeConstant.BATTLE, "等待区为空", data)));  //这里也必须传data,否则会导致空指针异常
        } else {
            //对GlobalDataStore.waitUser中随机取一个玩家
            int size = GlobalDataStore.waitUser.size();
            int index = (int) (Math.random() * size);
            String[] array = GlobalDataStore.waitUser.keySet().toArray(new String[0]);//把map中所有的键转换为数组
            WebSocket webSocket = GlobalDataStore.onlineUser.get(array[index]);  //随机取一个等待区中的值
            data.setOpponentName(array[index]);//把敌人设置到InitiateBattleDTO
            //匹配成功之后再次通知客户端，使客户端等待的异步任务完成
            conn.send(JSONUtil.toJsonStr(Result.success(SubmoduleTypeConstant.MATCH_BATTLE, ModuleTypeConstant.BATTLE, "匹配成功", data)));
            webSocket.send(JSONUtil.toJsonStr(Result.success(SubmoduleTypeConstant.ACCEPT_BATTLE_INVITATION, ModuleTypeConstant.BATTLE, "ok", data)));//发送邀请

        }
    }

    /**
     * 对于对战中退出游戏的处理
     *
     * @param conn   与客户端的通信对象
     * @param result 客户端数据
     */
    @Override
    public void battleQuit(WebSocket conn, Result result) {
        String opponentPlayerName = BattleUtils.getOpponentPlayerName(result.getData().toString());
        if (result.getMessage().contains("win")) {
//            String s = GlobalDataStore.onlineUser.keySet().stream().filter(i -> !i.equals(result.getData().toString())).findFirst().get();
            //2024年11月27日14:58:28   从对局中拿到对方信息
            GlobalDataStore.onlineUser.get(opponentPlayerName)
                    .send(JSONUtil.toJsonStr(Result.success(SubmoduleTypeConstant.BATTLE_QUIT
                            , ModuleTypeConstant.BATTLE
                            , result.getMessage())
                    ));
        } else {
            GlobalDataStore.onlineUser.get(result.getData().toString())
                    .send(JSONUtil.toJsonStr(Result.success(SubmoduleTypeConstant.BATTLE_QUIT
                            , ModuleTypeConstant.BATTLE
                            , result.getMessage())
                    ));
        }

        //调用该方法意味着对局进入了最后，则直接在服务端移除相关全局参数即可
        BattleUtils.removeGlobalBattleMessage(result.getData().toString(), opponentPlayerName);
    }

    /**
     * 根据经验提升等级
     *
     * @param conn   与客户端的通信对象
     * @param result 客户端数据
     */
    @Override
    public void upLevel(WebSocket conn, Result result) {
        int experience = Integer.parseInt(result.getMessage()); //获得的经验值
        int petId = Integer.parseInt(result.getData().toString());
        String userName = result.getFromUser();
        UserPet userPet = userPetDao.getUserPetByPetIdAndUsername(petId, userName);
        if (userPet == null) {
            log.error("pve出战宠物不存在");
        }else{
            if (userPet.getExp()+experience>100){
                //经验大于100则提升一级
                int additionalExp = experience-(100-userPet.getExp());//升级后剩下的经验值
                userPetDao.updateLeave(additionalExp,userPet.getLevel()+1,petId,userName);
                String message = "你获得了 "+experience+" 经验值，并把宠物等级升到了 "+(userPet.getLevel()+1)+" 级";
                //调用方法发送数据
                Result<Object> response = new Result<>();
                response.setModuleName(ModuleTypeConstant.BATTLE);
                response.setCommand(SubmoduleTypeConstant.EXPERIENCE);
                response.setMessage(message);
                conn.send(JSONUtil.toJsonStr(response));
            }else {
                userPetDao.updateExp(experience,petId,userName);
                String message = "你获得了 "+experience+" 经验值,"+"离升到下一级还剩 "+(100-(userPet.getExp()+experience))+" 经验值";
                //调用方法发送数据
                Result<Object> response = new Result<>();
                response.setModuleName(ModuleTypeConstant.BATTLE);
                response.setCommand(SubmoduleTypeConstant.EXPERIENCE);
                response.setMessage(message);
                conn.send(JSONUtil.toJsonStr(response));
            }
        }
    }



    /**
     * 给对战双方发送宠物列表
     *
     * @param data 对战数据
     */
    private void sendUserPetInfo(InitiateBattleDTO data) {
        GlobalDataStore.onlineUser.get(data.getInitiatorName())
                .send(JSONUtil.toJsonStr(Result.success(SubmoduleTypeConstant.SHOW_USER_PET_INFO
                        , ModuleTypeConstant.BATTLE
                        , battleDao.getUserPetList(data.getInitiatorName())
                        , data)));
        GlobalDataStore.onlineUser.get(data.getOpponentName())
                .send(JSONUtil.toJsonStr(Result.success(SubmoduleTypeConstant.SHOW_USER_PET_INFO
                        , ModuleTypeConstant.BATTLE
                        , battleDao.getUserPetList(data.getOpponentName())
                        , data)));
    }


    /**
     * 初始化战斗表和战斗宠物表
     *
     * @param data 对战数据
     * @return 对表的影响行数
     */
    private Long initBattleTableAndBPetTable(InitiateBattleDTO data) {
        return battleDao.initBattleTableAndBPetTable(data);

    }


}
